home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / sys / mac / macmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  23.1 KB  |  997 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)macmenu.c    3.1               93/04/29       */
  2. /*      Copyright (c) Macintosh NetHack Port Team, 1993.          */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /****************************************\
  6.  * Extended Macintosh menu support
  7.  *
  8.  * provides access to all keyboard commands from cmd.c
  9.  * provides control key functionality for classic keyboards
  10.  * provides key equivalent references and logical menu groups
  11.  * supports various menu highlighting modes
  12.  * does not (yet) provide balloon help support (maybe never will!)
  13. \****************************************/
  14.  
  15. /****************************************\
  16.  * Edit History:
  17.  *
  18.  * 930512    - More bug fixes and getting tty to work again, Jon W{tte
  19.  * 930508    - Bug fixes in-flight, Jon W{tte
  20.  * 04/29/93 - 1st Release Draft, David Hairston
  21.  * 04/11/93 - 1st Draft, David Hairston
  22. \****************************************/
  23.  
  24. /******** Application Defines ********/
  25. #include "hack.h"
  26. #include "patchlevel.h"
  27.  
  28. /******** Toolbox Defines ********/
  29. /* #include <Controls.h> */
  30. #include <Desk.h>
  31. /* #include <Dialogs.h> */
  32. /* #include <Memory.h> */
  33. #include <Menus.h>
  34. /* #include <Quickdraw.h> */
  35. #include <Resources.h>
  36. /* #include <SegLoad.h> */
  37. #include <TextEdit.h>
  38. #include <ToolUtils.h>
  39. #include <Packages.h>
  40. /* #include <Windows.h> */
  41.  
  42. /* Think/MPW incompatibility from Think.h/Script.h */
  43. #if !defined(__THINK__) && !defined(__SCRIPT__)
  44. #define GetMBarHeight()        (* (short *) 0x0BAA)
  45. #endif
  46.  
  47. /* Think/MPW incompatibility from LoMem.h/SysEqu.h */
  48. #if !defined(__LOMEM__) && !defined(__SYSEQU__)
  49. enum { WindowList = 0x9D6 };
  50. #endif
  51.  
  52. /* Think has separated out c2pstr and other pascal odditites */
  53. #if defined(THINK_C)
  54. #include <pascal.h>
  55. #endif
  56.  
  57. /******** Local Defines ********/
  58.  
  59. /* 'MNU#' (menu list record) */
  60. typedef union menuRefUnn
  61. {
  62.     short        mresID;        /* MENU resource ID (before GetMenu) */
  63.     MenuHandle    mhnd;        /* MENU handle (after GetMenu) */
  64. } menuRefUnn;
  65.  
  66. typedef struct menuListRec
  67. {
  68.     short        firstMenuID;
  69.     short        numMenus;
  70.     menuRefUnn    mref[];
  71. } menuListRec, *menuListPtr, **menuListHandle;
  72.  
  73. /* indices and resource IDs of the menu list data */
  74. enum
  75. {
  76.     listMenubar,
  77.     listSubmenu,
  78.  
  79.     menuBarListID = 128,
  80.     subMenuListID
  81. };
  82.  
  83. /* the following mref[] indices are reserved */
  84. enum
  85. {
  86.     /* menu bar */
  87.     menuApple,
  88.     menuFile,
  89.     menuEdit,
  90.  
  91.     /* submenu */
  92.     menuWizard = 0
  93. };
  94.  
  95. /* the following menu items are reserved */
  96. enum
  97. {
  98.     /* apple */
  99.     menuAppleAboutBox = 1,
  100.     ____Apple__1,
  101.  
  102.     /* File */
  103.     menuFileOpenMap = 1,
  104.     menuFileRedraw,
  105.     menuFilePrevMsg,
  106.     menuFileCleanup,
  107.     menuFileClose,
  108.     ____File___1,
  109.     menuFilePlayMode,
  110.     menuFileEnterExplore,
  111.     ____File___2,
  112.     menuFileOptionEdit,
  113.     ____File___3,
  114.     menuFileSave,
  115.     ____File___4,
  116.     menuFileQuit,
  117.  
  118.     /* standard minimum Edit menu items */
  119.  
  120.     /* Wizard */
  121.     menuWizardAttributes = 1
  122. };
  123.  
  124. /* symbols here correspond to arrays in DialogAskName */
  125. /* eventually this data will become a 'STR#' resource */
  126. static unsigned char    uitmChar[3][16] = {{"ABCEHKPRSTVW"}, {"MF"}, {" XD"}};
  127.  
  128.     /* arrays here correspond to symbols in drawANUserItem */
  129.     /* eventually this data will be moved to 'STR#' resources */
  130. static unsigned char * nhRole [ askn_role_end ] = {
  131.     {"\pArcheologist"}, {"\pBarbarian"},
  132.     {"\pCaveman"}, {"\pElf"}, {"\pHealer"}, {"\pKnight"},
  133.     {"\pPriest"}, {"\pRogue"}, {"\pSamurai"}, {"\pTourist"},
  134.     {"\pValkyrie"}, {"\pWizard"}
  135. };
  136. static unsigned char * nhSex [ 2 ] = {
  137.     {"\pMale"}, {"\pFemale"}
  138. };
  139. static unsigned char * nhMode [ 3 ] = {
  140.     {"\pRegular"}, {"\pExplore"}, {"\pDebug"}
  141. };
  142.  
  143.  
  144. /*
  145.  * menuListRec data (preloaded and locked) specifies the number of menus in
  146.  * the menu bar, the number of hierarchal or submenus and the menu IDs of
  147.  * all of those menus.  menus that go into in the menu bar are specified by
  148.  * 'MNU#' 128 and submenus are specified by 'MNU#' 129.  the fields of the
  149.  * menuListRec are:
  150.  * firstMenuID - the menu ID (not resource ID) of the 1st menu.  subsequent
  151.  *     menus in the list are _forced_ to have consecutively incremented IDs.
  152.  * numMenus - the total count of menus in a given list (and the extent of
  153.  *     valid menu IDs).
  154.  * mref[] - initially the MENU resource ID is stored in the placeholder for
  155.  *     the resource handle.  after loading (GetResource), the menu handle
  156.  *     is stored and the menu ID, in memory, is set as noted above.
  157.  *
  158.  * NOTE: a ResEdit template editor is supplied to edit the 'MNU#' resources.
  159.  *
  160.  * NOTE: the resource IDs do not need to match the menu IDs in a menu list
  161.  * record although they have been originally set that way.
  162.  *
  163.  * NOTE: the menu ID's of menus in the submenu list record may be reset, as
  164.  * noted above.  it is the programmers responsibility to make sure that
  165.  * submenu references/IDs are valid.
  166.  *
  167.  * WARNING: the existence of the submenu list record is assumed even if the
  168.  * number of submenus is zero.  also, no error checking is done on the
  169.  * extents of the menu IDs.  this must be correctly setup by the programmer.
  170.  */
  171.  
  172. #define ID1_MBAR    pMenuList[listMenubar]->firstMenuID
  173. #define ID1_SUBM    pMenuList[listSubmenu]->firstMenuID
  174.  
  175. #define NUM_MBAR    pMenuList[listMenubar]->numMenus
  176. #define NUM_SUBM    pMenuList[listSubmenu]->numMenus
  177.  
  178. #define MHND_APPLE    pMenuList[listMenubar]->mref[menuApple].mhnd
  179. #define MHND_FILE    pMenuList[listMenubar]->mref[menuFile].mhnd
  180. #define MHND_EDIT    pMenuList[listMenubar]->mref[menuEdit].mhnd
  181.  
  182. #define MBARHND(x)    pMenuList[listMenubar]->mref[(x)].mhnd
  183.  
  184. #define MHND_WIZ    pMenuList[listSubmenu]->mref[menuWizard].mhnd
  185.  
  186.  
  187. /* mutually exclusive (and prioritized) menu bar states */
  188. enum
  189. {
  190.     mbarDim,
  191.     mbarNoWindows,
  192.     mbarDA,
  193.     mbarNoMap,
  194.     mbarRegular,
  195.     mbarSpecial                    /* explore or debug mode */
  196. };
  197.  
  198. #define WKND_MAP        (WIN_BASE_KIND + NHW_MAP)
  199.  
  200.  
  201. /* menu routine error numbers */
  202. enum
  203. {
  204.     errGetMenuList,
  205.     errGetMenu,
  206.     errGetANDlogTemplate,
  207.     errGetANDlogItems,
  208.     errGetANDialog,
  209.     errANNewMenu,
  210.     err_Menu_total
  211. };
  212.  
  213.  
  214. /* menu 'STR#' comment char */
  215. #define mstrEndChar        0xA5        /* '\245' or option-* or "bullet" */
  216.  
  217. /* max key queue (from macwin.c) */
  218. #define QUEUE_LEN        keyQueueLen
  219. extern const int keyQueueLen ;
  220.  
  221. /* 'ALRT' */
  222. enum
  223. {
  224.     alrt_Menu_start = 5000,
  225.     alrtMenuNote = alrt_Menu_start,
  226.     alrtMenu_NY,
  227.     alrt_Menu_limit
  228. };
  229.  
  230. #define beepMenuAlertErr    1        /* # of SysBeep()'s before exitting */
  231. enum
  232. {
  233.     bttnMenuAlertNo = 1,
  234.     bttnMenuAlertYes
  235. };
  236.  
  237. /* askname menus */
  238. enum
  239. {
  240.     menuANRole,
  241.     menuANSex,
  242.     menuANMode,
  243.     menuAN_total
  244. };
  245.  
  246.  
  247. /******** Globals ********/
  248. static    unsigned char *menuErrStr[err_Menu_total] = 
  249.     {
  250.         "\pAbort: Bad \'MNU#\' resource!",        /* errGetMenuList */
  251.         "\pAbort: Bad \'MENU\' resource!",        /* errGetMenu */
  252.         "\pAbort: Bad \'DLOG\' resource!",        /* errGetANDlogTemplate */
  253.         "\pAbort: Bad \'DITL\' resource!",        /* errGetANDlogItems */
  254.         "\pAbort: Bad Dialog Allocation!",        /* errGetANDialog */
  255.         "\pAbort: Bad Menu Allocation!",        /* errANNewMenu */
  256.     };
  257. static    menuListPtr    pMenuList[2];
  258. static    short        theMenubar = mbarDA;    /* force initial update */
  259. static    short        kAdjustWizardMenu = 1;
  260.  
  261.  
  262. /******** Prototypes ********/
  263. static    void alignAD(Rect *, short);
  264. static    void mustGetMenuAlerts(void);
  265. static    void menuError(short);
  266.  
  267. extern    void AddToKeyQueue ( int ch , Boolean force ) ;
  268. pascal    void drawANUserItem(WindowPtr, short);
  269.         void DialogAskName(asknameRec *);
  270.         void InitMenuRes(void);
  271.         void AdjustMenus(short);
  272.         void DoMenuEvt(long);
  273. extern    void WindowGoAway(EventRecord *, WindowPtr);
  274.  
  275. static    void aboutNetHack(void);
  276. static    void openMap(void);
  277. static    void closeFrontWindow(void);
  278. static    void optionEditor(void);
  279. static    void askSave(void);
  280. static    void askQuit(void);
  281.  
  282.  
  283. /******** Routines ********/
  284. static void
  285. alignAD(Rect *pRct, short vExempt)
  286. {
  287.     (*pRct).right -= (*pRct).left;        /* width */
  288.     (*pRct).bottom -= (*pRct).top;        /* height */
  289.     (*pRct).left = (qd.screenBits.bounds.right - (*pRct).right) / 2;
  290.     (*pRct).top = (qd.screenBits.bounds.bottom - (*pRct).bottom - vExempt) / 2;
  291.     (*pRct).top += vExempt;
  292.     (*pRct).right += (*pRct).left;
  293.     (*pRct).bottom += (*pRct).top;
  294. }
  295.  
  296. static void
  297. mustGetMenuAlerts()
  298. {
  299.     short        i, mbarHgt = GetMBarHeight();
  300.     Rect        **hRct;
  301.  
  302.     for (i = alrt_Menu_start; i < alrt_Menu_limit; i++)
  303.     {
  304.         if (! (hRct = (Rect **) GetResource('ALRT', i)))    /* AlertTHndl */
  305.         {
  306.             for (i = 0; i < beepMenuAlertErr; i++)
  307.                 SysBeep(3);
  308.             ExitToShell();
  309.         }
  310.  
  311.         alignAD(*hRct, mbarHgt);
  312.     }
  313. }
  314.  
  315. static void
  316. menuError(short menuErr)
  317. {
  318.     short    i;
  319.  
  320.     for (i = 0; i < beepMenuAlertErr; i++)
  321.         SysBeep(3);
  322.  
  323.     ParamText(menuErrStr[menuErr], "\p", "\p", "\p");
  324.     (void) Alert(alrtMenuNote, (ModalFilterProcPtr) 0L);
  325.  
  326.     ExitToShell();
  327. }
  328.  
  329. pascal void
  330. drawANUserItem(WindowPtr wPtr, short uItm)
  331. {
  332.     asknameRec    *pANR;
  333.     short        iTyp;
  334.     Handle        iHnd;
  335.     Rect        iRct;
  336.     short        whichUserItem;
  337.  
  338.     pANR = (asknameRec *) GetWRefCon(wPtr);
  339.     GetDItem((DialogPtr) wPtr, uItm, &iTyp, &iHnd, &iRct);
  340.  
  341.     switch (uItm)
  342.     {
  343.     case uitmANOutlineDefault:
  344.         PenSize(3, 3);
  345.         FrameRoundRect(&iRct, 16, 16);
  346.         break;
  347.  
  348.     case uitmANRole:
  349.     case uitmANSex:
  350.     case uitmANMode:
  351.         whichUserItem = uItm - uitmANRole;
  352.  
  353.         PenNormal();
  354.         EraseRect(&iRct);
  355.  
  356.         /* drop shadow */
  357.         iRct.right--;
  358.         iRct.bottom--;
  359.         MoveTo(iRct.right, (iRct.top + 1));
  360.         LineTo(iRct.right, iRct.bottom);
  361.         LineTo((iRct.left + 1), iRct.bottom);
  362.  
  363.         /* frame */
  364.         FrameRect(&iRct);
  365.  
  366.         /* menu character */
  367.         MoveTo((iRct.left + 2), (iRct.top + 12));
  368.         DrawChar(uitmChar[whichUserItem][(*pANR).anMenu[whichUserItem]]);
  369.  
  370.         /* popup symbol */
  371.         MoveTo((iRct.left + 18), (iRct.top + 6));
  372.         LineTo((iRct.left + 28), (iRct.top + 6));
  373.         LineTo((iRct.left + 23), (iRct.top + 11));
  374.         LineTo((iRct.left + 19), (iRct.top + 7));
  375.         LineTo((iRct.left + 26), (iRct.top + 7));
  376.         LineTo((iRct.left + 23), (iRct.top + 10));
  377.         LineTo((iRct.left + 21), (iRct.top + 8));
  378.         LineTo((iRct.left + 24), (iRct.top + 8));
  379.         LineTo((iRct.left + 23), (iRct.top + 9));
  380.         break;
  381.     }
  382. }
  383.  
  384. /* this routine manages the extended askname dialog */
  385. void
  386. DialogAskName(asknameRec *pANR)
  387. {
  388.     GrafPtr            pOldPort;
  389.     DialogTHndl        dTHnd;
  390.     Handle            dIHnd;
  391.     DialogRecord    dRec;
  392.     short            i, iHit, iTyp;
  393.     Handle            iHnd;
  394.     Rect            iRct, iRct2;
  395.     MenuHandle        mhndAskName[menuAN_total];
  396.     short            mbarHgt = GetMBarHeight();
  397.     short            ndxItem, menuEntry;
  398.     Point            pt;
  399.  
  400.     if (! (dTHnd = (DialogTHndl) GetResource('DLOG', dlogAskName)))
  401.         menuError(errGetANDlogTemplate);
  402.     alignAD((Rect *) *dTHnd, mbarHgt);
  403.  
  404.     if (! (dIHnd = GetResource('DITL', dlogAskName)))
  405.         menuError(errGetANDlogItems);
  406.  
  407.     GetPort(&pOldPort);
  408.     /* to do: check if theWorld.hasColorQD ... */
  409.     (void) GetNewDialog(dlogAskName, (Ptr) &dRec, (WindowPtr) 0L);
  410.     if (ResError() || MemError())
  411.         menuError(errGetANDialog);
  412.  
  413.     SetWRefCon((WindowPtr) &dRec, (long) pANR);
  414.     for (i = 0; i < menuAN_total; i++) {
  415.         if (! (mhndAskName[i] = NewMenu((dlogAskName + i), "\pPopup")))
  416.             menuError(errANNewMenu);
  417.     }
  418.  
  419.     /* role menu */
  420.     for (i = 0; i < askn_role_end; i++)
  421.         AppendMenu(mhndAskName[menuANRole], * (Str255 *) nhRole[i]);
  422.  
  423.     /* sex menu */
  424.     for (i = 0; i < 2; i++)
  425.         AppendMenu(mhndAskName[menuANSex], * (Str255 *) nhSex[i]);
  426.  
  427.     /* mode menu */
  428.     for (i = 0; i < 3; i++)
  429.         AppendMenu(mhndAskName[menuANMode], * (Str255 *) nhMode[i]);
  430.  
  431.     /* insert the popup menus */
  432.     for (i = 0; i < menuAN_total; i++)
  433.         InsertMenu(mhndAskName[i], hierMenu);
  434.  
  435.     for (i = uitmANOutlineDefault; i <= uitmANMode; i++)
  436.     {
  437.         GetDItem((DialogPtr)&dRec, i, &iTyp, &iHnd, &iRct);
  438.         SetDItem((DialogPtr)&dRec, i, iTyp, (Handle) drawANUserItem, &iRct);
  439.     }
  440.     {
  441.     short kind ; Handle item ; Rect area ;
  442.     Str32 pName ;
  443.         pName [ 0 ] = 0 ;
  444.         if ( plname && plname [ 0 ] ) {
  445.             strcpy ( ( char * ) pName , plname ) ;
  446.             c2pstr ( ( char * ) pName ) ;
  447.         } else {
  448.             Handle h ;
  449.             h = GetResource ( 'STR ' , -16096 ) ;
  450.             if ( ( (Handle) NULL != h ) && ( GetHandleSize ( h ) > 0 ) ) {
  451.                 DetachResource ( h ) ;
  452.                 HLock ( h ) ;
  453.                 if ( * * h > 31 ) {
  454.                     * * h = 31 ;
  455.                 }
  456.                 BlockMove ( * h , pName , * * h + 1 )  ;
  457.                 DisposeHandle ( h ) ;
  458.             }
  459.         }
  460.         if ( pName [ 0 ] ) {
  461.             GetDItem ( ( WindowPtr ) & dRec , etxtANWho , & kind , & item , & area ) ;
  462.             SetIText ( item , pName ) ;
  463.             if ( pName [ 0 ] > 2 && pName [ pName [ 0 ] - 1 ] == '-' ) {
  464.                 (*pANR).anMenu[anRole] = ( strchr ( (char *) uitmChar [ 0 ] , pName [ pName [ 0 ] ] ) -
  465.                     (char *) uitmChar [ 0 ] ) ;
  466.             }
  467.         }
  468.     }
  469.     SelIText ( ( WindowPtr ) & dRec , etxtANWho , 0 , 32767 ) ;
  470.  
  471.     SetPort((GrafPtr) &dRec);
  472.     ShowWindow((WindowPtr) &dRec);
  473.     SelectWindow((WindowPtr) &dRec);
  474.  
  475.     iHit = bttnANQuit + 1;
  476.     while (iHit > bttnANQuit)
  477.     {
  478.         /* adjust the askname menus */
  479.         {
  480.             static short    checkFeatures = 1;
  481.             static short    currRole = -1, currSex = -1;
  482.             unsigned char    anCavePerson[2][16] = {{"\pCaveman"}, {"\pCavewoman"}};
  483.             unsigned char    anCleric[2][16] = {{"\pPriest"}, {"\pPriestess"}};
  484.  
  485.             if (checkFeatures)
  486.             {
  487.                 checkFeatures = 0;
  488.  
  489. #ifndef TOURIST
  490.                 DisableItem(mhndAskName[menuANRole], (asknTourist + 1));
  491. #endif
  492. #ifndef WIZARD
  493.                 DisableItem(mhndAskName[menuANMode], (asknDebug + 1));
  494. #endif
  495. #ifndef EXPLORE_MODE
  496.                 DisableItem(mhndAskName[menuANMode], (asknExplore + 1));
  497. #endif
  498.             }
  499.  
  500.             /* check role 1st, valkyrie forces female */
  501.             if (currRole != (*pANR).anMenu[anRole])
  502.             {
  503.                 currRole = (*pANR).anMenu[anRole];
  504.  
  505.                 if ((*pANR).anMenu[anRole] == asknValkyrie)
  506.                 {
  507.                     (*pANR).anMenu[anSex] = asknFemale;
  508.  
  509.                     GetDItem((DialogPtr) &dRec, uitmANSex, &iTyp, &iHnd, &iRct);
  510.                     InvalRect(&iRct);
  511.  
  512.                     /* disable male sex option */
  513.                     DisableItem(mhndAskName[menuANSex], (asknMale + 1));
  514.                 }
  515.                 else
  516.                     /* enable male sex option */
  517.                     EnableItem(mhndAskName[menuANSex], (asknMale + 1));
  518.             }
  519.  
  520.             if (currSex != (*pANR).anMenu[anSex])
  521.             {
  522.                 currSex = (*pANR).anMenu[anSex];
  523.  
  524.                 SetItem(mhndAskName[menuANRole], (asknCaveman + 1),
  525.                         * (Str255 *) anCavePerson[currSex]);
  526.                 SetItem(mhndAskName[menuANRole], (asknPriest + 1),
  527.                         * (Str255 *) anCleric[currSex]);
  528.             }
  529.         }
  530.  
  531.         ModalDialog((ModalFilterProcPtr) 0L, &iHit);
  532.  
  533.         switch (iHit)
  534.         {
  535.         case bttnANPlay:        /* done!  let's play */
  536.             break;
  537.  
  538.         case bttnANQuit:
  539.             (*pANR).anMenu[anMode] = asknQuit;
  540.             break;
  541.  
  542.         case uitmANRole:
  543.         case uitmANSex:
  544.         case uitmANMode:
  545.             ndxItem = iHit - uitmANRole;
  546.  
  547.             /* invert the popup title */
  548.             GetDItem((DialogPtr) &dRec, (iHit + 3), &iTyp, &iHnd, &iRct2);
  549.             InvertRect(&iRct2);
  550.  
  551.             /* get the menu item */
  552.             GetDItem((DialogPtr) &dRec, iHit, &iTyp, &iHnd, &iRct);
  553.             pt = * (Point *) &iRct;
  554.             LocalToGlobal(&pt);
  555.             if (menuEntry = PopUpMenuSelect(mhndAskName[ndxItem],
  556.                             pt.v, pt.h, ((*pANR).anMenu[ndxItem] + 1)))
  557.                 /* set last item selected */
  558.                 (*pANR).anMenu[ndxItem] = LoWord(menuEntry) - 1;
  559.  
  560.             InvertRect(&iRct2);
  561.             InvalRect(&iRct);
  562.             break;
  563.  
  564.         case etxtANWho:
  565.             /* limit the data here to 25 chars */
  566.             {
  567.                 short beepTEDelete = 1;
  568.  
  569.                 while ((**dRec.textH).teLength > 25)
  570.                 {
  571.                     if (beepTEDelete++ <= 3)
  572.                         SysBeep(3);
  573.                     TEKey('\b', dRec.textH);
  574.                 }
  575.             }
  576.  
  577.             /* special case filter (that doesn't plug all the holes!) */
  578.             if (((**dRec.textH).teLength == 1) && (**((**dRec.textH).hText) < 32))
  579.                 TEKey('\b', dRec.textH);
  580.  
  581.             /* if no name then disable the play button */
  582.             GetDItem((DialogPtr) &dRec, bttnANPlay, &iTyp, &iHnd, &iRct);
  583.             if ((**dRec.textH).teLength > 0)
  584.                 iTyp &= ~itemDisable;
  585.             else
  586.                 iTyp |= itemDisable;
  587.             HiliteControl((ControlHandle) iHnd, ((iTyp & itemDisable) ? 255 : 0));
  588.             SetDItem((DialogPtr) &dRec, bttnANPlay, iTyp, iHnd, &iRct);
  589.             break;
  590.         }
  591.     }
  592.  
  593.     if ((*pANR).anMenu[anMode] != asknQuit) {
  594. /*
  595.  * This is a good example of how NOT to get text from a dialog
  596.  *
  597.  *        HLock((Handle) (**dRec.textH).hText);
  598.  *        BlockMove(*((**dRec.textH).hText), &((*pANR).anWho[1]), (**dRec.textH).teLength);
  599.  *        (*pANR).anWho[0] = (**dRec.textH).teLength;
  600.  *        HUnlock((Handle) (**dRec.textH).hText);
  601.  */
  602.         short kind ; Rect outline ; Handle item ;
  603.         Str32 pName ;
  604.  
  605.         GetDItem ( ( WindowPtr ) & dRec , etxtANWho , & kind , & item , & outline ) ;
  606.          GetIText ( item , ( * pANR ) . anWho ) ;
  607.         BlockMove ( pANR -> anWho , pName , pANR -> anWho [ 0 ] + 1 ) ;
  608.         if ( pName [ 0 ] > 2 && pName [ pName [ 0 ] - 1 ] == '-' ) {
  609.             (*pANR).anMenu[anRole] = ( strchr ( (char *) uitmChar [ 0 ] , pName [ pName [ 0 ] ] ) -
  610.                 (char *) uitmChar [ 0 ] ) ;
  611.         }
  612.     }
  613.  
  614.     /* cleanup (in reverse order) and leave */
  615.     for (i = 0; i < menuAN_total; i++)
  616.     {
  617.         DeleteMenu(dlogAskName + i);
  618.         DisposeMenu(mhndAskName[i]);
  619.     }
  620.     CloseDialog((DialogPtr)&dRec);
  621.     DisposHandle(dRec.items);
  622.     ReleaseResource(dIHnd);
  623.     ReleaseResource((Handle) dTHnd);
  624.     SetPort(pOldPort);
  625. }
  626.  
  627. void
  628. InitMenuRes()
  629. {
  630. static Boolean was_inited = 0 ;
  631. short            i, j;
  632. menuListHandle    mlHnd;
  633. MenuHandle        mHnd;
  634.  
  635.     if ( was_inited ) {
  636.         return ;
  637.     }
  638.     was_inited = 1 ;
  639.  
  640.     mustGetMenuAlerts();
  641.  
  642.     for (i = listMenubar; i <= listSubmenu; i++)
  643.     {
  644.         if (! (mlHnd = (menuListHandle) GetResource('MNU#', (menuBarListID + i))))
  645.             menuError(errGetMenuList);
  646.  
  647.         pMenuList[i] = *mlHnd;
  648.  
  649.         for (j = 0; j < (**mlHnd).numMenus; j++)
  650.         {
  651.             if (! (mHnd = (MenuHandle) GetMenu((**mlHnd).mref[j].mresID))) {
  652.             Str31 d ;
  653.                 NumToString ( (**mlHnd).mref[j].mresID , d ) ;
  654. //                DebugStr ( d ) ;
  655.                 menuError(errGetMenu);
  656.             }
  657.  
  658.             (**mlHnd).mref[j].mhnd = mHnd;
  659.             * ((short *) *mHnd) = j + (**mlHnd).firstMenuID;    /* consecutive IDs */
  660.  
  661.             /* expand apple menu */
  662.             if ((i == listMenubar) && (j == menuApple)) {
  663.                 AddResMenu(mHnd, 'DRVR');
  664.             }
  665.  
  666.             InsertMenu(mHnd, ((i == listSubmenu) ? hierMenu : 0));
  667.         }
  668.     }
  669.  
  670.     DrawMenuBar();
  671. }
  672.  
  673. void
  674. AdjustMenus(short dimMenubar)
  675. {
  676. short        newMenubar = mbarRegular;
  677. WindowPeek    peekWindow = (WindowPeek) FrontWindow();
  678. short        i;
  679.  
  680. /*
  681.  *    if ( windowprocs != mac_procs ) {
  682.  *        return ;
  683.  *    }
  684.  */
  685.     /* determine the new menubar state */
  686.     if (dimMenubar) {
  687.         newMenubar = mbarDim;
  688.     } else if (! peekWindow) {
  689.         newMenubar = mbarNoWindows;
  690.     } else if (peekWindow->windowKind < 0) {
  691.         newMenubar = mbarDA;
  692.     } else {
  693.         while (peekWindow && (peekWindow->windowKind != WKND_MAP)) {
  694.             peekWindow = peekWindow->nextWindow;
  695.         }
  696.         if ((! peekWindow) || (! peekWindow->visible)) {
  697.             newMenubar = mbarNoMap;
  698.         }
  699.     }
  700.  
  701.     if (newMenubar != mbarRegular)
  702.         ;                            /* we've already found its state */
  703. #ifdef WIZARD
  704.     else if (wizard)
  705.     {
  706.         newMenubar = mbarSpecial;
  707.  
  708.         if (kAdjustWizardMenu)
  709.         {
  710.             kAdjustWizardMenu = 0;
  711.  
  712.             SetItem(MHND_FILE, menuFilePlayMode, "\pDebug");
  713.         }
  714.     }
  715. #endif
  716.  
  717. #ifdef EXPLORE_MODE
  718.     else if (discover)
  719.     {
  720.         newMenubar = mbarSpecial;
  721.  
  722.         if (kAdjustWizardMenu)
  723.         {
  724.             kAdjustWizardMenu = 0;
  725.  
  726.             SetItem(MHND_FILE, menuFilePlayMode, "\pExplore");
  727.  
  728.             for (i = CountMItems(MHND_WIZ); i > menuWizardAttributes; i--)
  729.                 DelMenuItem(MHND_WIZ, i);
  730.         }
  731.     }
  732. #endif
  733.  
  734.     /* adjust the menubar, if there's a state change */
  735.     if (theMenubar != newMenubar)
  736.     {
  737.         switch(theMenubar = newMenubar)
  738.         {
  739.         case mbarDim:
  740.             /* disable all menus (except the apple menu) */
  741.             for (i = menuFile; i < NUM_MBAR; i++)
  742.                 DisableItem(MBARHND(i), 0);
  743.             break;
  744.  
  745.         case mbarNoWindows:
  746.         case mbarDA:
  747.         case mbarNoMap:
  748.             /* enable the file menu, but ... */
  749.             EnableItem(MHND_FILE, 0);
  750.  
  751.             if (theMenubar == mbarDA)
  752.                 DisableItem(MHND_FILE, menuFileOpenMap);
  753.             else
  754.                 EnableItem(MHND_FILE, menuFileOpenMap);
  755.  
  756.             /* ... disable the window commands! */
  757.             for (i = menuFileRedraw; i <= menuFileEnterExplore; i++)
  758.                 DisableItem(MHND_FILE, i);
  759.  
  760.             if (theMenubar != mbarNoWindows)
  761.                 EnableItem(MHND_FILE, menuFileClose);
  762.  
  763.             /* ... and disable the rest of the menus */
  764.             for (i = menuEdit; i < NUM_MBAR; i++)
  765.                 DisableItem(MBARHND(i), 0);
  766.  
  767.             if (theMenubar == mbarDA)
  768.                 EnableItem(MHND_EDIT, 0);
  769.  
  770.             break;
  771.  
  772.         case mbarRegular:
  773.         case mbarSpecial:
  774.             /* enable all menus ... */
  775.             for (i = menuFile; i < NUM_MBAR; i++)
  776.                 EnableItem(MBARHND(i), 0);
  777.  
  778.             /* ... except the unused Edit menu */
  779.             DisableItem(MHND_EDIT, 0);
  780.  
  781.             /* ... the map is already open! */
  782.             DisableItem(MHND_FILE, menuFileOpenMap);
  783.  
  784.             /* ... enable the window commands */
  785.             for (i = menuFileRedraw; i <= menuFileEnterExplore; i++)
  786.                 EnableItem(MHND_FILE, i);
  787.  
  788.             if (theMenubar == mbarRegular)
  789.                 DisableItem(MHND_FILE, menuFilePlayMode);
  790.             else
  791.                 DisableItem(MHND_FILE, menuFileEnterExplore);
  792.  
  793.             break;
  794.         }
  795.  
  796.         DrawMenuBar();
  797.     }
  798. }
  799.  
  800. void
  801. DoMenuEvt(long menuEntry)
  802. {
  803.     short menuID = HiWord(menuEntry);
  804.     short menuItem = LoWord(menuEntry);
  805.  
  806.     switch(menuID - ID1_MBAR)    /* all submenus are default case */
  807.     {
  808.     case menuApple:
  809.         if (menuItem == menuAppleAboutBox)
  810.             aboutNetHack();
  811.         else
  812.         {
  813.             unsigned char daName[32];
  814.  
  815.             GetItem(MHND_APPLE, menuItem, * (Str255 *) daName);
  816.             (void) OpenDeskAcc(daName);
  817.         }
  818.         break;
  819.  
  820.     /*
  821.      * Those direct calls are ugly: they should be installed into cmd.c .
  822.      * Those AddToKeyQueue() calls are also ugly: they should be put into
  823.      * the 'STR#' resource.
  824.      */
  825.     case menuFile:
  826.         switch(menuItem)
  827.         {
  828.         case menuFileOpenMap:
  829.             openMap();
  830.             break;
  831.  
  832.         case menuFileRedraw:
  833.             AddToKeyQueue ( 'R' & 0x1f , 1 ) ;
  834.             break;
  835.  
  836.         case menuFilePrevMsg:
  837.             AddToKeyQueue ( 'P' & 0x1f , 1 ) ;
  838.             break;
  839.  
  840.         case menuFileCleanup:
  841.             (void) SanePositions();
  842.             break;
  843.  
  844.         case menuFileClose:
  845.             closeFrontWindow();
  846.             break;
  847.  
  848.         case menuFileEnterExplore:
  849.             AddToKeyQueue ( 'X' , 1 ) ;
  850.             break;
  851.  
  852.         case menuFileOptionEdit:
  853.             optionEditor();
  854.             break;
  855.  
  856.         case menuFileSave:
  857.             askSave();
  858.             break;
  859.  
  860.         case menuFileQuit:
  861.             askQuit();
  862.             break;
  863.         }
  864.         break;
  865.  
  866.     case menuEdit:
  867.         (void) SystemEdit(menuItem - 1);
  868.         break;
  869.  
  870.     default:    /* get associated string and add to key queue */
  871.         {
  872.             Str255    mstr;
  873.             short    i;
  874.  
  875.             GetIndString(mstr, menuID, menuItem);
  876.             if (mstr[0] > QUEUE_LEN)
  877.                 mstr[0] = QUEUE_LEN;
  878.  
  879.             for (i = 1; ((i <= mstr[0]) && (mstr[i] != mstrEndChar)); i++)
  880.                 AddToKeyQueue(mstr[i], false);
  881.         }
  882.         break;
  883.     }
  884.  
  885.     HiliteMenu(0);
  886. }
  887.  
  888.  
  889. static void
  890. aboutNetHack() {
  891.     if (theMenubar >= mbarRegular) {
  892.         (void) doversion();                /* is this necessary? */
  893.     } else {
  894.     unsigned char aboutStr[32] = "\pNetHack 3.1.";
  895.  
  896.         if (PATCHLEVEL > 10) {
  897.             aboutStr[++aboutStr[0]] = '0'+PATCHLEVEL/10;
  898.         }
  899.  
  900.         aboutStr[++aboutStr[0]] = '0' + (PATCHLEVEL % 10);
  901.  
  902.         ParamText(aboutStr, "\p\rnethack-bugs@linc.cis.upenn.edu", "\p", "\p");
  903.         (void) Alert(alrtMenuNote, (ModalFilterProcPtr) 0L);
  904.         ResetAlrtStage();
  905.     }
  906. }
  907.  
  908. static void
  909. openMap()
  910. {
  911.     WindowPeek    peekWindow = *(WindowPeek*) WindowList;
  912.  
  913.     while (peekWindow && (peekWindow->windowKind != WKND_MAP))
  914.         peekWindow = peekWindow->nextWindow;
  915.  
  916.     if (! peekWindow)
  917.         return;                /* impossible? */
  918.  
  919.     ShowWindow((WindowPtr) peekWindow);
  920.     SelectWindow((WindowPtr) peekWindow);
  921. }
  922.  
  923. static void
  924. closeFrontWindow()
  925. {
  926.     WindowPeek    peekWindow = (WindowPeek) FrontWindow();
  927.  
  928.     if (! peekWindow)
  929.         return;                /* impossible? */
  930.     else if (peekWindow->windowKind < 0)
  931.         CloseDeskAcc(peekWindow->windowKind);
  932.     else if (peekWindow->windowKind == WKND_MAP)
  933.         HideWindow((WindowPtr) peekWindow);
  934.     else
  935.         WindowGoAway((EventRecord *) 0L, (WindowPtr) peekWindow);
  936. }
  937.  
  938. static void
  939. optionEditor()
  940. {
  941.     ParamText("\pSorry, not yet implemented!  Use Options on the Help menu.", "\p", "\p", "\p");
  942.     (void) Alert(alrtMenuNote, (ModalFilterProcPtr) 0L);
  943.     ResetAlrtStage();
  944. }
  945.  
  946. static void
  947. askSave() {
  948. Boolean doSave = 1 ;
  949. Boolean doYes = 0 ;
  950.  
  951.     if (theMenubar < mbarRegular) {
  952.     short    itemHit;
  953.  
  954.         ParamText("\pReally Save?", "\p", "\p", "\p");
  955.         itemHit = Alert(alrtMenu_NY, (ModalFilterProcPtr) 0L);
  956.         ResetAlrtStage();
  957.  
  958.         if (itemHit != bttnMenuAlertYes) {
  959.             doSave = 0 ;
  960.         } else {
  961.             doYes = 1 ;
  962.         }
  963.     }
  964.     if ( doSave ) {
  965.         AddToKeyQueue ( 'S' , 1 ) ;
  966.         if ( doYes ) {
  967.             AddToKeyQueue ( 'y' , 1 ) ;
  968.         }
  969.     }
  970. }
  971.  
  972. static void
  973. askQuit() {
  974. Boolean doQuit = 1 ;
  975. Boolean doYes = 0 ;
  976.  
  977.     if (theMenubar < mbarRegular) {
  978.     short    itemHit;
  979.  
  980.         ParamText("\pReally Quit?", "\p", "\p", "\p");
  981.         itemHit = Alert(alrtMenu_NY, (ModalFilterProcPtr) 0L);
  982.         ResetAlrtStage();
  983.  
  984.         if (itemHit != bttnMenuAlertYes) {
  985.             doQuit = 0 ;
  986.         } else {
  987.             doYes = 1 ;
  988.         }
  989.     }
  990.     if ( doQuit ) {
  991.         AddToKeyQueue ( 'Q' , 1 ) ;
  992.         if ( doYes ) {
  993.             AddToKeyQueue ( 'y' , 1 ) ;
  994.         }
  995.     }
  996. }
  997.